package com.yuelan.apartment.service.impl;

import com.yuelan.apartment.common.Constant;
import com.yuelan.apartment.domain.ApaRoomInfo;
import com.yuelan.apartment.domain.ApartmentInfo;
import com.yuelan.apartment.domain.TenantInfo;
import com.yuelan.apartment.domain.dto.RentBillDto;
import com.yuelan.apartment.domain.dto.TenantDto;
import com.yuelan.apartment.domain.vo.TenantVo;
import com.yuelan.apartment.mapper.ApartmentMapper;
import com.yuelan.apartment.mapper.TenantMapper;
import com.yuelan.apartment.service.RentService;
import com.yuelan.apartment.service.RoomService;
import com.yuelan.apartment.service.TenantService;
import com.yuelan.common.core.constant.HttpStatus;
import com.yuelan.common.core.context.SecurityContextHolder;
import com.yuelan.common.core.exception.ServiceException;
import com.yuelan.common.core.utils.DateUtils;
import com.yuelan.common.core.utils.bean.BeanUtils;
import com.yuelan.common.core.utils.uuid.IdWorker;
import com.yuelan.common.core.web.page.PageDomain;
import com.yuelan.common.core.web.page.TableDataInfo;
import com.yuelan.common.core.web.page.TableSupport;
import com.yuelan.common.redis.service.RedisService;
import com.yuelan.common.security.handler.GlobalExceptionHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @description: 租户管理
 * @Author: ZhaoYi
 * @date: 24-5-23 17:00
 */
@Service
public class TenantServiceImpl implements TenantService {

    @Autowired
    private TenantMapper tenantMapper;

    @Autowired
    private RoomService roomService;

    @Autowired
    private ApartmentMapper apartmentMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private RentService rentService;

    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);


    @Transactional
    @Override
    public int add(TenantDto tenantDto) {
        tenantDto.setId(IdWorker.snowflake());
        tenantDto.setCreate_time(DateUtils.getNowDate());
        roomService.addRoom(getRoomInfo(tenantDto));
        TenantInfo tenantInfo = tenantMapper.selectTenant(tenantDto.getPhone() , tenantDto.getId_number());
        if (tenantInfo != null) {
            throw new ServiceException(Constant.TENANT_SERVICE_EXIST);
        }
        rentService.createRentBill(getRentBillInfo(tenantDto));
        return tenantMapper.insert(getTenantInfo(tenantDto));
    }

    private TenantInfo getTenantInfo(TenantDto tenantDto) {
        TenantInfo tenantInfo = new TenantInfo();
        tenantInfo.setId(tenantDto.getId());
        tenantInfo.setRoom_id(tenantDto.getRoom_id());
        tenantInfo.setName(tenantDto.getName());
        tenantInfo.setPhone(tenantDto.getPhone());
        tenantInfo.setId_number(tenantDto.getId_number());
        tenantInfo.setApartment_id(tenantDto.getApartment_id());
        tenantInfo.setCreate_time(DateUtils.getNowDate());
        tenantInfo.setEnd_time(tenantDto.getEnd_time());
        return tenantInfo;
    }

    private RentBillDto getRentBillInfo(TenantDto tenantDto) {
        RentBillDto rentBillDto = new RentBillDto();
        rentBillDto.setId(tenantDto.getId());
        rentBillDto.setApartmentId(tenantDto.getApartment_id());
        rentBillDto.setTenantId(tenantDto.getId());
        rentBillDto.setRoomId(tenantDto.getRoom_id());
        rentBillDto.setCollectionTime(tenantDto.getCollectionTime());
        rentBillDto.setAmount(tenantDto.getAmount());
        rentBillDto.setPaymentType(tenantDto.getPaymentType());
        rentBillDto.setStatus("Uncollected");
        rentBillDto.setCreateTime(DateUtils.getNowDate());
        rentBillDto.setContractEndDate(tenantDto.getEnd_time());
        return rentBillDto;
    }

    private ApaRoomInfo getRoomInfo(TenantDto tenantDto) {
        ApaRoomInfo apaRoomInfo = new ApaRoomInfo();
        apaRoomInfo.setTenants_id(tenantDto.getId());
        apaRoomInfo.setRoom_id(tenantDto.getRoom_id());
        apaRoomInfo.setApartment_id(tenantDto.getApartment_id());
        apaRoomInfo.setTenants_id(tenantDto.getId());
        apaRoomInfo.setFloor(tenantDto.getFloor());
        apaRoomInfo.setState(0);
        apaRoomInfo.setArea(tenantDto.getArea());
        apaRoomInfo.setWater(tenantDto.getWater());
        apaRoomInfo.setPower(tenantDto.getPower());
        apaRoomInfo.setType(tenantDto.getType());
        return apaRoomInfo;
    }


    /**
     * 假分页
     * @param tenantInfo
     * @return TableDataInfo
     */
    @Override
    public TableDataInfo list(TenantInfo tenantInfo) {
        Long userId = SecurityContextHolder.getUserId();
        String cacheKey = userId + Constant.TENANT_KEY;
        List<TenantVo> cacheList = redisService.getCacheList(cacheKey);
        if (cacheList.size() != 0) {
            return pageModel(cacheList);
        }
        List<ApartmentInfo> apartmentList = apartmentMapper.selectAllHouse(userId);
        List<TenantVo> tenantVoList = new ArrayList<>();
        for (ApartmentInfo apartmentItem: apartmentList) {
            tenantMapper.selectTenantList(apartmentItem.getId())
                        .stream().map(tenant -> {
                                TenantVo tenantVo = new TenantVo();
                                BeanUtils.copyBeanProp(tenantVo, tenant);
                                tenantVo.setApartment_name(apartmentItem.getApartment_name());
                                return tenantVoList.add(tenantVo);
                        }).collect(Collectors.toList());
        }
        redisService.setCacheList(cacheKey, tenantVoList);
        return pageModel(tenantVoList);
    }
    private TableDataInfo pageModel(List<TenantVo> tenantVoList) {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        TableDataInfo rspData = new TableDataInfo();
        List<TenantVo> res = tenantVoList
                .stream().skip((pageNum - 1) * pageSize).limit(pageSize).toList();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setRows(res);
        rspData.setTotal(tenantVoList.size());
        return rspData;
    }

    /**
     * 真分页
     * @param tenantInfo
     * @return TableDataInfo
     */
    @Override
    public TableDataInfo page(TenantInfo tenantInfo) {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        List<ApartmentInfo> apartmentList = apartmentMapper.selectAllHouse(SecurityContextHolder.getUserId());
        List<Long> houseId = apartmentList.stream().map(ApartmentInfo::getId).toList();
        List<TenantVo> tenantVoList = tenantMapper.listTenant(houseId,
                (pageDomain.getPageNum()-1) * pageDomain.getPageSize() , pageDomain.getPageSize());
        int total = apartmentList.stream().mapToInt(item -> tenantMapper.total(item.getId())).sum();
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setRows(tenantVoList);
        rspData.setTotal(total);
        return rspData;
    }


    @Transactional
    @Override
    public int delete(Long id) {
        if (id == null) {
            throw new ServiceException(Constant.SERVICE_ERROR);
        }
        return tenantMapper.delete(id);
    }


    @Transactional
    @Override
    public int deleteTenantByIds(Long[] ids) {
        if (ids == null) {
            throw new ServiceException(Constant.SERVICE_ERROR);
        }
        roomService.updateRoomState(ids);
        return tenantMapper.deleteTenantByIds(ids);
    }


    @Transactional
    @Override
    public int update(TenantInfo tenantInfo) {
        return tenantMapper.update(tenantInfo);
    }


    @Override
    public TenantInfo load(Long id) {
        if (id == null) {
            throw new ServiceException(Constant.SERVICE_ERROR);
        }
        return tenantMapper.load(id);
    }


    @Override
    public List<TenantInfo> pageList(TenantInfo tenantInfo) {
        return tenantMapper.pageList(tenantInfo);
    }


}
